package cn.org.itool.ws.framework.utils;

import cn.hutool.core.collection.CollectionUtil;
import cn.org.itool.ws.framework.netty.auth.Principal;
import cn.org.itool.ws.framework.netty.message.BizWsMessage;
import cn.org.itool.ws.framework.protocol.factory.ProtocolServiceFactory;
import cn.org.itool.ws.framework.protocol.service.ProtocolService;
import cn.org.itool.ws.framework.ws.WsServer;
import cn.org.itool.ws.framework.ws.group.WsDefaultChannelGroup;
import cn.org.itool.ws.pojo.UserTag;
import io.netty.channel.Channel;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class ChannelGroupUtil {

    private final static ConcurrentMap<String, WsDefaultChannelGroup> channelGroupMap =new ConcurrentHashMap<>();


    /**
     * grouping channels
     *
     * @param principal {@link Principal}
     * @param channel {@link Channel}
     * @return true 添加成功
     */
    public static boolean addToGroup(Principal principal, Channel channel){
        List<Channel> oChannels = new ArrayList<>(1);
        boolean success = ChannelGroupUtil.put(channel, principal, oChannels, principal.getGroupName());
        if(success && !oChannels.isEmpty()){
            oChannels.forEach(ChannelUtils::forceOffline);
        }
        return success;
    }



    public static boolean put(Channel channel, Principal principal, List<Channel> oChannels, String groupName) {
        WsDefaultChannelGroup group = getGroupByName(groupName);
        return group.put(channel, principal, oChannels);
    }

    public static WsDefaultChannelGroup getGroupByName(String groupName) {
        WsDefaultChannelGroup channelGroup = channelGroupMap.get(groupName);
        if(Objects.nonNull(channelGroup)) {
            return channelGroup;
        }
        return createGroupByName(groupName);
    }

    public static Set<String> getUserIdByName(String groupName) {
        WsDefaultChannelGroup channelGroup = channelGroupMap.get(groupName);
        if(Objects.isNull(channelGroup)) {
            return null;
        }
        return channelGroup.priIdAll();
    }

    /**
     * 在线用户数
     * @return 数量
     */
    public static int onlineCount() {
        int count = 0;
        for (WsDefaultChannelGroup value : channelGroupMap.values()) {
            count += value.onlineCount();
        }
        return count;
    }

    public static Set<UserTag> getUserTagByName(String groupName) {
        WsDefaultChannelGroup channelGroup = channelGroupMap.get(groupName);
        if(Objects.isNull(channelGroup)) {
            return null;
        }
        return channelGroup.userTagAll();
    }

    public static synchronized WsDefaultChannelGroup createGroupByName(String groupName) {
        WsDefaultChannelGroup channelGroup = channelGroupMap.get(groupName);
        if(Objects.nonNull(channelGroup)) {
            return channelGroup;
        }

        channelGroup = new WsDefaultChannelGroup(groupName);
        channelGroupMap.put(groupName, channelGroup);
        return channelGroup;
    }

    public static void writeAndFlush(String groupName, List<String> includeUserIds, List<String> ignoreUserIds, BizWsMessage msg) {
        WsDefaultChannelGroup channelGroup = channelGroupMap.get(groupName);
        if(Objects.isNull(channelGroup) || Objects.isNull(msg)) {
            return;
        }

        channelGroup.writeAndFlush(msg, (item)-> {

            boolean inFlag = CollectionUtil.isEmpty(includeUserIds) || ChannelUtils.containsUser(item, includeUserIds);
            boolean igFlag = CollectionUtil.isEmpty(ignoreUserIds) || !ChannelUtils.containsUser(item, ignoreUserIds);
            return inFlag && igFlag;
        });
    }

    public static void closeAll() {
        for (WsDefaultChannelGroup value : channelGroupMap.values()) {
            value.closeAll();
        }
    }

    public static void classByWsIds(Set<String> wsIds) {
        for (WsDefaultChannelGroup value : channelGroupMap.values()) {
            value.classByWsIds(wsIds);
        }
    }
}
